package com.hefan.live.service;

import com.alibaba.fastjson.JSON;
import com.cat.common.entity.ResultBean;
import com.cat.common.meta.ResultCode;
import com.cat.tiger.util.GlobalConstants;
import com.hefan.common.ons.service.ONSProducer;
import com.hefan.common.util.MapUtils;
import com.hefan.live.bean.*;
import com.hefan.live.dao.LiveLogDao;
import com.hefan.live.dao.LiveRoomDao;
import com.hefan.live.itf.LiveImOptService;
import com.hefan.live.itf.LiveLogService;
import com.hefan.live.itf.LivingRedisOptService;
import com.hefan.live.itf.RoomEnterExitOptService;
import com.hefan.notify.itf.ItemsStaticService;
import com.hefan.oms.itf.AnchorTicketDayService;
import com.hefan.oms.itf.RedPacketService;
import com.hefan.user.bean.WebUser;
import com.hefan.user.itf.WebUserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.profiler.Profiler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

/**
 * Created by nigle on 2016/9/26.
 */
@Component("liveLogService")
public class LiveLogServiceImpl implements LiveLogService {
    public Logger logger = LoggerFactory.getLogger(LiveLogServiceImpl.class);

    @Resource
    LiveLogDao liveLogDao;
    @Resource
    LiveRoomDao liveRoomDao;
    @Resource
    AnchorTicketDayService anchorTicketDayService;
    @Resource
    WebUserService userService;
    @Resource
    LiveImOptService liveImOptlService;
    @Resource
    RedPacketService redPacketService;
    @Resource
    ItemsStaticService itemsStaticService;
    @Resource
    ONSProducer onsProducer;
    @Resource
    RoomEnterExitOptService roomEnterExitOptService;
    @Resource
    LivingRedisOptService livingRedisOptService;
    @Resource
    WebUserService webUserService;

    @Transactional(readOnly=true)
    public LiveLog getLiveLogByUuid(String liveUuid){
        return liveLogDao.getLiveLogByUuid(liveUuid);
    }

    /**
     * 直播开启初始化任务
     * @param liveRoom
     * @param liveLog
     * @return
     */
    @Override
    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
    public void liveStartOperate(LiveRoom liveRoom, LiveLog liveLog ) throws Exception {
        // 更新直播间的房间号和直播封面
        int a = liveRoomDao.updateLiveRoomWhenLiveStart(liveRoom);
        if (a != 1)
            throw new Exception("开播liveRoom和liveLog操作异常，事务回滚");

        int b = liveLogDao.insterLiveLog(liveLog);
        if (b != 1)
            throw new Exception("开播liveRoom和liveLog操作异常，事务回滚");
    }

    @Override
    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
    public int updateLiveLogForRebalance(LiveLog liveLog) {
        return liveLogDao.updateLiveLogForRebalance(liveLog);
    }

    /**
     * 关播处理
     * @param liveLog
     * @return
     */
    @Override
    public LiveLog liveEndOperate(LiveLog liveLog) {
        //结算时长
        Profiler profiler=new Profiler("关播开始");
        Long liveLength = (liveLog.getEndTime().getTime() - liveLog.getStartTime().getTime())/1000;
        liveLog.setLiveLength(liveLength);
        liveLog.setValidLiveLength(liveLength);
        liveLog.setAbnormal_end(0);//正常关播为0
        liveLog.setOptUser(0);
        //关播主线程，更新livelog和liveRoom
        profiler.start("调用关播主业务");
        try {
            liveEndMain(liveLog);
        }catch (Exception d){
            return null;
        }
        //关播辅线程，异步清理
        profiler.start("调用关播辅业务");
        liveEndAux(liveLog);
        profiler.stop().print();
        logger.info("直播:{}结束成功",liveLog.getLiveUuid());
        return liveLog;
    }

    /**
     * 关播处理主线程
     */
    @Override
    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
    public void liveEndMain(LiveLog liveLog)throws Exception {
        Profiler profiler=new Profiler("关播主业务开始");
        // 清除直播信息
        profiler.start("清除直播信息");
        long ldelLive = livingRedisOptService.delLivingInfo_Hash(liveLog.getUserId());
        if (ldelLive == -1){
            logger.info("删除redis中-LIVING_ROOM_HASH_KEY-直播信息 结果：" + ldelLive);
            throw new Exception("关播清除redis中直播信息-LIVING_ROOM_HASH_KEY-操作异常，事务回滚");
        }

        // 直播结束 将直播间直播状态置为未直播
        profiler.start("live_room表操作");
        int b = liveRoomDao.updateLiveRoomWhenLiveEnd(liveLog.getUserId());
        if (b != 1) {
            throw new Exception("关播liveRoom操作异常，事务回滚");
        }
        // 直播结束后更新结束时间和播放时长
        profiler.start("live_log表操作");
        int a = liveLogDao.updateLiveLogByEnd(liveLog);
        if (a != 1) {
            throw new Exception("关播liveLog操作异常，事务回滚");
        }
        profiler.stop().print();
        logger.info("直播:{}结束成功",liveLog.getLiveUuid());
    }

    /**
     * 关播处理：清理房间观众、机器人、未领红包
     */
    @Override
    @Async
    public void liveEndAux(LiveLog liveLog) {
        try {
            List list = livingRedisOptService.getAllUserIdInRoom(liveLog.getUserId());
            //清理直播间观众及机器人
            roomEnterExitOptService.endLiveClear(liveLog.getUserId());
            //更新peopleCount
            itemsStaticService.peopleCount();
            //更新热门、最新直播列表页
            itemsStaticService.getLivingList();
            //清理红包数据
            redPacketService.updateRedPackOrderStatus(liveLog.getLiveUuid());
            //清除本次直播收入缓存--设置两小时缓存失效时间
            livingRedisOptService.delTicketCountByUuid(liveLog.getLiveUuid());
            //清除本次直播真实人数缓存
            livingRedisOptService.delLivingUserCountReal(liveLog.getUserId());
            //同步历史盒饭数到web_user中
            try {
                webUserService.incrWebUserHefanFromCach(liveLog.getUserId());
            } catch (Exception e) {
                e.printStackTrace();
            }
            //清理check数据
            clearCheck(list,liveLog.getUserId());
            //清理关播后额外人数
            livingRedisOptService.setAddNumForRoom(liveLog.getUserId(), "0");
        }catch (Exception e){
            logger.info("关播辅线程错误");
        }
    }

    /**
     * 关播清理check数据
     * @param list 观众IDs
     */
    private void clearCheck(List list, String anchId) {
        try {
            if (null != list || list.size() > 0) {
                for (Object item : list) {
                    try {
                        String userId = (String) item;
                        String mapStr = livingRedisOptService.getUserEnterLivingInfo_Hash(userId);
                        if ( null == mapStr ) return;
                        Map map = JSON.parseObject(mapStr, Map.class);
                        String _anthId = MapUtils.getStrValue(map, "authId", "");// 主播id
                        String _userId = MapUtils.getStrValue(map, "userId", "");// 进入直播间用户id
                        if (anchId.equals(_anthId) && userId.equals(_userId)) {
                            livingRedisOptService.delUserEnterLivingInfo_Hash(userId);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("getLivingUserList_SortedSet  解析错误", e);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("清理check信息失败");
        }
    }

    @Override
    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
    public int changeWatchNum(String liveUuid, int chatRoomId, int addNum) {
        return liveLogDao.changeWatchNum(liveUuid, chatRoomId, addNum);
    }

    @Override
    @Transactional(readOnly=true)
    public LiveLog getLiveLogByLiveTime(String roomId, String liveTime) {
        return this.liveLogDao.getLiveLogByLiveTime(roomId, liveTime);
    }

    /**
     * 查询正在直播的liveLog
     * @return
     */
    @Override
    @Transactional(readOnly=true)
    public LiveLog getLivingLiveLog(String userId){
        return liveLogDao.getLivingLiveLog(userId);
    }

    /**
     * 非正常关播
     * map:{"liveUuid":"","type":1}
     * 来源：1表示后台关闭，2表示心跳失联关闭,3,监控
     *
     * @return {"result":1，"msg":"成功"}
     */
    @Override
    public ResultBean liveExcEnd(String liveUuid, int from,String promptCopy) {
        ResultBean result = new ResultBean();
        LiveLog liveLog = liveLogDao.getLiveLogByUuid(liveUuid);
        //关播数据结算
        WebUser user = userService.getWebUserInfoByUserId(liveLog.getUserId());
        //结束时间、时长
        String infoRedis = null;
        try {
            infoRedis = livingRedisOptService.getLivingHeartBeatInfo(liveUuid);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(infoRedis)) {
            LivingHeartBeatVo livingHeartBeatVo = JSON.parseObject(infoRedis, LivingHeartBeatVo.class);
            if (null != livingHeartBeatVo && livingHeartBeatVo.getChatRoomId() > 0
                    && StringUtils.isNotBlank(livingHeartBeatVo.getLiveUuid())
                    && StringUtils.isNotBlank(livingHeartBeatVo.getAuthoruserId())
                    && livingHeartBeatVo.getUpdateTime() > 0) {
                Timestamp tt = new Timestamp(livingHeartBeatVo.getUpdateTime());
                liveLog.setEndTime(tt);
            }
        } else {
            liveLog.setEndTime(liveLog.getStartTime());
        }
        long liveLength = (liveLog.getEndTime().getTime() - liveLog.getStartTime().getTime()) / 1000;
        liveLog.setLiveLength(liveLength);
        liveLog.setValidLiveLength(liveLength);
        liveLog.setOptUser(from);//关闭来源,2表示来自心跳
        liveLog.setAbnormal_end(GlobalConstants.ERR_LIVE_END);//异常关闭为1

        //观看人数
        long num = liveLog.getWatchNum();
        String watchNum = null;
        try {
            watchNum = livingRedisOptService.getLivingWatchNum(liveLog.getLiveUuid());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(watchNum)) {
            num = Long.valueOf(watchNum);
        }
        try {
            String addNUm = livingRedisOptService.getAddNumForRoom(liveLog.getUserId());
            if (null != addNUm && Long.valueOf(addNUm) >= 0) {
                num += Long.valueOf(addNUm);
                logger.info("{}加入了{}额外人数", liveLog.getUserId(), addNUm);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        liveLog.setWatchNum(num);
        //更新live_log和live_room
        try {
            liveEndMain(liveLog);
        } catch (Exception d) {
            result.setCode(ResultCode.UNSUCCESS.get_code());
            return result;
        }
        //异步处理更新直播间列表、红包、直播间观众
        liveEndAux(liveLog);

        //发送IM消息,发送三次
        if(from == 3){
            liveImOptlService.liveBand(user,liveLog.getChatRoomId(), liveUuid,String.valueOf(num),String.valueOf(liveLog.getLiveLength()), String.valueOf(liveLog.getTicketCount()),promptCopy);
            liveImOptlService.liveBand(user,liveLog.getChatRoomId(), liveUuid,String.valueOf(num),String.valueOf(liveLog.getLiveLength()),String.valueOf(liveLog.getTicketCount()),promptCopy);
            liveImOptlService.liveBand(user,liveLog.getChatRoomId(), liveUuid,String.valueOf(num),String.valueOf(liveLog.getLiveLength()),String.valueOf(liveLog.getTicketCount()),promptCopy);
        }
        liveImOptlService.liveEndIm(user, liveLog.getChatRoomId(), liveUuid, String.valueOf(num), String.valueOf(liveLog.getLiveLength()), String.valueOf(liveLog.getTicketCount()));
        liveImOptlService.liveEndIm(user, liveLog.getChatRoomId(), liveUuid, String.valueOf(num), String.valueOf(liveLog.getLiveLength()), String.valueOf(liveLog.getTicketCount()));
        liveImOptlService.liveEndIm(user, liveLog.getChatRoomId(), liveUuid, String.valueOf(num), String.valueOf(liveLog.getLiveLength()), String.valueOf(liveLog.getTicketCount()));

        logger.info("心跳失联，关闭直播成功，liveUuid：" + liveUuid);
        result.setCode(ResultCode.SUCCESS.get_code());
        return result;
    }

    /**
     * 监控端修改直播封面或直播描述
     * @param liveName 直播描述
     * @param liveImg 直播封面
     * @param liveUuid 直播uuid
     * @param anthId 主播id
     */
    public ResultBean updateLiveInfoForMonitor(String liveName, String liveImg, String liveUuid, String anthId){
        logger.info("updateLiveInfoForMonitor-----begin");
        if( !livingRedisOptService.isExistsLivingInfo_Hash(anthId)){
            logger.info("updateLiveInfoForMonitor------直播间不在直播状态");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        String livingInfoStr = livingRedisOptService.getLivingInfo_Hash(anthId);
        if (StringUtils.isBlank(livingInfoStr)) {
            logger.info("updateLiveInfoForMonitor----取redis信息失败");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        LivingRoomInfoVo vo = JSON.parseObject(livingInfoStr, LivingRoomInfoVo.class);
        if (null == vo) {
            logger.info("updateLiveInfoForMonitor----取redis信息失败");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        logger.info("updateLiveInfoForMonitor----取出缓存中主播直播信息--" + vo.getPersonSign() + "---" + vo.getLiveImg());
        if(StringUtils.isBlank(liveImg)){
        	liveImg = vo.getLiveImg();
        }
        if(StringUtils.isBlank(liveName)){
        	liveName = vo.getPersonSign();
        }
        if (vo.getPersonSign().equals(liveName) && vo.getLiveImg().equals(liveImg)) {
            logger.info("updateLiveInfoForMonitor----本次无修改项");
            return new ResultBean(ResultCode.SUCCESS);
        }
        vo.setLiveImg(liveImg);
        vo.setPersonSign(liveName);
        livingRedisOptService.addLivingInfo_Hash(anthId, JSON.toJSONString(vo));
        String livingInfoStr_ = livingRedisOptService.getLivingInfo_Hash(anthId);
        if (StringUtils.isBlank(livingInfoStr_)) {
            logger.info("updateLiveInfoForMonitor---取redis信息失败");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        LivingRoomInfoVo vo_ = JSON.parseObject(livingInfoStr_, LivingRoomInfoVo.class);
        if (null == vo_) {
            logger.info("updateLiveInfoForMonitor---取redis信息失败");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        logger.info("updateLiveInfoForMonitor----更改后的缓存中主播直播信息--" + vo_.getPersonSign() + "---" + vo_.getLiveImg());
        if (!vo_.getPersonSign().equals(liveName) || !vo_.getLiveImg().equals(liveImg)) {
            logger.info("updateLiveInfoForMonitor----更改redis信息失败");
            return new ResultBean(ResultCode.UNSUCCESS);
        }
        try {
            updateDBForMonitor(liveName, liveImg, liveUuid, anthId);
        } catch (Exception e) {
            logger.info("updateLiveInfoForMonitor----DB操作失败");
        }
        //更新热门、最新直播列表页
        itemsStaticService.getLivingList();
        logger.info("updateLiveInfoForMonitor-----end");
        return new ResultBean(ResultCode.SUCCESS);
    }

    /**
     * 更改直播名称和描述
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    private void updateDBForMonitor(String liveName, String liveImg, String liveUuid, String anthId) throws Exception {

      int b = liveRoomDao.updateLiveRoomForMonitor( liveImg, liveName, anthId);
      if (b != 1)
        throw new Exception("updateLiveInfoForMonitor---修改liveRoom操作异常，事务回滚");

      int a = liveLogDao.updateLiveLogForMonitor(  liveImg, liveName, liveUuid);
      if (a != 1)
        throw new Exception("updateLiveInfoForMonitor---修改liveLog操作异常，事务回滚");
    }
    /**
     * 更新VIP直播间状态
     * @param livingRoomInfoVo
     * @return
     */
    @Override
    public ResultBean updateVIPLiveStatus(LivingRoomInfoVo livingRoomInfoVo) {
        ResultBean resultBean = new ResultBean(ResultCode.SUCCESS);
        try {
            roomEnterExitOptService.setLivingRoomInfo(livingRoomInfoVo);
            liveLogDao.updateVIPLiveLogStatus(livingRoomInfoVo);
            //更新直播列表
            itemsStaticService.getLivingList();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultBean;
    }

  /**
   * 查询在start和end区间关播所有主播间
   * @description （用一句话描述该方法的适用条件、执行流程、适用方法、注意事项 - 可选）
   * @author wangchao
   * @create 2016/12/28 15:13
   */
  @Override
  public List<LiveLog> getLiveLogByEndTime(String startTime, String endTime) throws Exception {
    return liveLogDao.getLiveLogByEndTime(startTime, endTime);
  }


}